#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

/**
 * 代码量统计工具
 * 统计项目中各种类型文件的代码行数
 */

// 配置项
const CONFIG = {
  // 需要统计的文件扩展名
  extensions: {
    'TypeScript': ['.ts', '.tsx'],
    'JavaScript': ['.js', '.jsx'],
    'CSS/LESS/SCSS': ['.css', '.less', '.scss', '.sass'],
    'HTML': ['.html', '.htm'],
    'JSON': ['.json'],
    'Markdown': ['.md', '.markdown'],
    'Config': ['.yml', '.yaml', '.toml', '.ini'],
    'Other': ['.txt', '.xml']
  },
  
  // 需要忽略的目录
  ignoreDirs: [
    'node_modules',
    '.git',
    'dist',
    'build',
    'coverage',
    '.next',
    '.nuxt',
    'out',
    'public',
    'static',
    'assets/images',
    'assets/icons'
  ],
  
  // 需要忽略的文件
  ignoreFiles: [
    '.gitignore',
    '.eslintrc',
    '.prettierrc',
    'package-lock.json',
    'yarn.lock',
    'pnpm-lock.yaml'
  ]
};

class CodeStats {
  constructor() {
    this.stats = {
      totalFiles: 0,
      totalLines: 0,
      totalCodeLines: 0,
      totalBlankLines: 0,
      totalCommentLines: 0,
      fileTypes: {}
    };
    
    // 初始化文件类型统计
    Object.keys(CONFIG.extensions).forEach(type => {
      this.stats.fileTypes[type] = {
        files: 0,
        lines: 0,
        codeLines: 0,
        blankLines: 0,
        commentLines: 0
      };
    });
  }

  /**
   * 判断是否应该忽略该目录
   */
  shouldIgnoreDir(dirName) {
    return CONFIG.ignoreDirs.some(ignore => 
      dirName === ignore || dirName.startsWith(ignore)
    );
  }

  /**
   * 判断是否应该忽略该文件
   */
  shouldIgnoreFile(fileName) {
    return CONFIG.ignoreFiles.some(ignore => 
      fileName === ignore || fileName.endsWith(ignore)
    );
  }

  /**
   * 获取文件类型
   */
  getFileType(filePath) {
    const ext = path.extname(filePath).toLowerCase();
    
    for (const [type, extensions] of Object.entries(CONFIG.extensions)) {
      if (extensions.includes(ext)) {
        return type;
      }
    }
    
    return null;
  }

  /**
   * 分析单个文件的代码行数
   */
  analyzeFile(filePath) {
    try {
      const content = fs.readFileSync(filePath, 'utf-8');
      const lines = content.split('\n');
      
      let codeLines = 0;
      let blankLines = 0;
      let commentLines = 0;
      
      const ext = path.extname(filePath).toLowerCase();
      const isJsTs = ['.js', '.jsx', '.ts', '.tsx'].includes(ext);
      const isCss = ['.css', '.less', '.scss', '.sass'].includes(ext);
      
      let inBlockComment = false;
      
      for (let line of lines) {
        const trimmedLine = line.trim();
        
        // 空行
        if (trimmedLine === '') {
          blankLines++;
          continue;
        }
        
        // JavaScript/TypeScript 注释检测
        if (isJsTs) {
          // 检查块注释开始
          if (trimmedLine.includes('/*')) {
            inBlockComment = true;
          }
          
          // 检查块注释结束
          if (trimmedLine.includes('*/')) {
            inBlockComment = false;
            commentLines++;
            continue;
          }
          
          // 在块注释中
          if (inBlockComment) {
            commentLines++;
            continue;
          }
          
          // 单行注释
          if (trimmedLine.startsWith('//')) {
            commentLines++;
            continue;
          }
        }
        
        // CSS 注释检测
        if (isCss) {
          if (trimmedLine.includes('/*')) {
            inBlockComment = true;
          }
          
          if (trimmedLine.includes('*/')) {
            inBlockComment = false;
            commentLines++;
            continue;
          }
          
          if (inBlockComment) {
            commentLines++;
            continue;
          }
        }
        
        // HTML 注释检测
        if (ext === '.html' || ext === '.htm') {
          if (trimmedLine.startsWith('<!--') || trimmedLine.includes('<!--')) {
            commentLines++;
            continue;
          }
        }
        
        // 代码行
        codeLines++;
      }
      
      return {
        totalLines: lines.length,
        codeLines,
        blankLines,
        commentLines
      };
      
    } catch (error) {
      console.warn(`无法读取文件: ${filePath}`, error.message);
      return {
        totalLines: 0,
        codeLines: 0,
        blankLines: 0,
        commentLines: 0
      };
    }
  }

  /**
   * 递归扫描目录
   */
  scanDirectory(dirPath) {
    try {
      const items = fs.readdirSync(dirPath);

      for (const item of items) {
        const fullPath = path.join(dirPath, item);

        let stat;
        try {
          stat = fs.statSync(fullPath);
        } catch (error) {
          // 跳过无法访问的文件/目录
          continue;
        }

        if (stat.isDirectory()) {
          // 跳过忽略的目录
          if (this.shouldIgnoreDir(item)) {
            continue;
          }

          // 递归扫描子目录
          this.scanDirectory(fullPath);
        } else if (stat.isFile()) {
          // 跳过忽略的文件
          if (this.shouldIgnoreFile(item)) {
            continue;
          }

          // 跳过过大的文件 (>10MB)
          if (stat.size > 10 * 1024 * 1024) {
            console.warn(`跳过大文件: ${fullPath} (${(stat.size / 1024 / 1024).toFixed(1)}MB)`);
            continue;
          }

          // 获取文件类型
          const fileType = this.getFileType(fullPath);
          if (!fileType) {
            continue;
          }

          // 分析文件
          const analysis = this.analyzeFile(fullPath);

          // 更新统计
          this.stats.totalFiles++;
          this.stats.totalLines += analysis.totalLines;
          this.stats.totalCodeLines += analysis.codeLines;
          this.stats.totalBlankLines += analysis.blankLines;
          this.stats.totalCommentLines += analysis.commentLines;

          // 更新文件类型统计
          const typeStats = this.stats.fileTypes[fileType];
          typeStats.files++;
          typeStats.lines += analysis.totalLines;
          typeStats.codeLines += analysis.codeLines;
          typeStats.blankLines += analysis.blankLines;
          typeStats.commentLines += analysis.commentLines;

          // 显示进度
          if (this.stats.totalFiles % 25 === 0) {
            process.stdout.write(`\r已扫描 ${this.stats.totalFiles} 个文件...`);
          }
        }
      }
    } catch (error) {
      console.warn(`\n无法扫描目录: ${dirPath}`, error.message);
    }
  }

  /**
   * 格式化数字显示
   */
  formatNumber(num) {
    return num.toLocaleString();
  }

  /**
   * 生成统计报告
   */
  generateReport() {
    console.log('\n\n📊 代码量统计报告');
    console.log('='.repeat(60));
    
    // 总体统计
    console.log('\n📈 总体统计:');
    console.log(`  总文件数: ${this.formatNumber(this.stats.totalFiles)}`);
    console.log(`  总行数: ${this.formatNumber(this.stats.totalLines)}`);
    console.log(`  代码行数: ${this.formatNumber(this.stats.totalCodeLines)}`);
    console.log(`  空白行数: ${this.formatNumber(this.stats.totalBlankLines)}`);
    console.log(`  注释行数: ${this.formatNumber(this.stats.totalCommentLines)}`);
    
    // 按文件类型统计
    console.log('\n📋 按文件类型统计:');
    console.log('-'.repeat(80));
    console.log('类型'.padEnd(15) + '文件数'.padEnd(10) + '总行数'.padEnd(12) + '代码行'.padEnd(12) + '空白行'.padEnd(12) + '注释行');
    console.log('-'.repeat(80));
    
    // 按代码行数排序
    const sortedTypes = Object.entries(this.stats.fileTypes)
      .filter(([_, stats]) => stats.files > 0)
      .sort(([, a], [, b]) => b.codeLines - a.codeLines);
    
    for (const [type, stats] of sortedTypes) {
      console.log(
        type.padEnd(15) +
        this.formatNumber(stats.files).padEnd(10) +
        this.formatNumber(stats.lines).padEnd(12) +
        this.formatNumber(stats.codeLines).padEnd(12) +
        this.formatNumber(stats.blankLines).padEnd(12) +
        this.formatNumber(stats.commentLines)
      );
    }
    
    // 代码质量指标
    console.log('\n📊 代码质量指标:');
    const commentRatio = ((this.stats.totalCommentLines / this.stats.totalCodeLines) * 100).toFixed(1);
    const blankRatio = ((this.stats.totalBlankLines / this.stats.totalLines) * 100).toFixed(1);
    const codeRatio = ((this.stats.totalCodeLines / this.stats.totalLines) * 100).toFixed(1);
    
    console.log(`  注释率: ${commentRatio}%`);
    console.log(`  空白行占比: ${blankRatio}%`);
    console.log(`  代码行占比: ${codeRatio}%`);
    
    // 平均每个文件的行数
    const avgLinesPerFile = (this.stats.totalLines / this.stats.totalFiles).toFixed(1);
    const avgCodeLinesPerFile = (this.stats.totalCodeLines / this.stats.totalFiles).toFixed(1);
    
    console.log(`  平均每文件行数: ${avgLinesPerFile}`);
    console.log(`  平均每文件代码行数: ${avgCodeLinesPerFile}`);
    
    console.log('\n✅ 统计完成!');
  }

  /**
   * 运行统计
   */
  run(targetPath = '.') {
    console.log('🚀 开始统计代码量...');
    console.log(`📁 扫描目录: ${path.resolve(targetPath)}`);
    
    const startTime = Date.now();
    
    this.scanDirectory(targetPath);
    
    const endTime = Date.now();
    const duration = ((endTime - startTime) / 1000).toFixed(2);
    
    console.log(`\n⏱️  扫描耗时: ${duration}秒`);
    
    this.generateReport();
  }
}

// 主程序
if (require.main === module) {
  const targetPath = process.argv[2] || '.';
  const codeStats = new CodeStats();
  codeStats.run(targetPath);
}

module.exports = CodeStats;
